using System;
using System.Linq;
using System.Collections.Generic;
using Foreglance.MVP.Helpers;
using Foreglance.MVP.Delegates;
using Foreglance.MVP.Models;
using Foreglance.MVP.Views;
using Foreglance.MVP.Views.Builders;
using Foreglance.MVP.Views.Properties;

namespace Foreglance.MVP.Presenters
{
    public abstract class AbstractEntityViewPresenter<TEntity, TModel, TBuilder> : IEntityViewPresenter<TEntity>
        where TModel : class, IModel<TEntity>, new()
        where TBuilder : IViewBuilder
    {
        private IViewBuilder _viewBuilder;
        private List<IViewProperty> _viewProperties;
        private IView _view;
        private TModel _model;

        public event ObjectListEventHandler<TEntity> OnRefreshView;
        public event ObjectListEventHandler<TEntity> OnEntitiesAdded;
        public event ObjectListEventHandler<TEntity> OnEntitiesEdited;
        public event ObjectListEventHandler<TEntity> OnEntitiesDeleted;
        public event ObjectListEventHandler<TEntity> OnEntitiesSelectionChanged;

        public IView View
        {
            get
            {
                return _view ?? (_view = new View());
            }
        }

        public void Init()
        {
            ViewBuilder.Build(this);
            if (OnEntitiesSelectionChanged != null)
                OnEntitiesSelectionChanged(this, Model.SelectedEntities);
        }

        public virtual void Begin()
        {
            Model.LoadEntities();
            RefreshView();
        }

        public void RefreshView()
        {
            if(OnRefreshView != null)
                OnRefreshView(this, Model.Entities);
            RefreshSelectedEntities();
        }

        public void SelectEntity(TEntity entity)
        {
            if (Model.SelectedEntities.Contains(entity))
                throw new InvalidOperationException("Selecting entity is already selected");
            Model.SelectedEntities.Add(entity);
            RefreshSelectedEntities();
        }

        public void UnselectEntity(TEntity entity)
        {
            if(!Model.SelectedEntities.Contains(entity))
                return;
            Model.SelectedEntities.Remove(entity);
            RefreshSelectedEntities();
        }

        public void SelectEntities(List<TEntity> entities)
        {
            if (OnEntitiesSelectionChanged != null)
                OnEntitiesSelectionChanged(this, entities);
        }

        public void AddEntity()
        {
            //TODO
        }

        public void EditEntity()
        {
            //TODO
        }

        public void SaveEntity(TEntity entity)
        {
            
        }

        public void DeleteEntities()
        {
            var entities = Model.SelectedEntities;
            if(entities.Count == 0
               || !MessageDialog.Confirm("Do you want to delete?"))
                return;
            Model.DeleteEntities();
        }

        public bool ValidateAddingEnabled(List<TEntity> entities)
        {
            return true;
        }

        public bool ValidateEditingEnabled(List<TEntity> entities)
        {
            return entities.Count == 1;
        }

        public bool ValidateDeletingEnabled(List<TEntity> entities)
        {
            return entities.Count > 0;
        }

        protected TModel Model
        {
            get
            {
                if (_model == null)
                {
                    _model = Repository.GetInstance<TModel>();
                    _model.OnEntitiesAdded += (sender, entities) => FireEntitiesEvent(OnEntitiesAdded, entities);
                    _model.OnEntitiesEdited += (sender, entities) => FireEntitiesEvent(OnEntitiesEdited, entities);
                    _model.OnEntitiesDeleted += (sender, entities) => FireEntitiesEvent(OnEntitiesDeleted, entities);
                }
                return _model;
            }
        }

        private void FireEntitiesEvent(ObjectListEventHandler<TEntity> eventHandler, List<TEntity> entities)
        {
            if (eventHandler != null)
                eventHandler(this, entities);
        }

        protected IViewBuilder ViewBuilder
        {
            get { return _viewBuilder ?? (_viewBuilder = ViewBuilderFactory.Instance.Create<TBuilder>()); }
        }

        public List<IViewProperty> ViewProperties
        {
            get { return _viewProperties ?? (_viewProperties = CreateViewProperties().ToList()); }
        }

        protected abstract IEnumerable<IViewProperty> CreateViewProperties();

        private void RefreshSelectedEntities()
        {
            SelectEntities(Model.SelectedEntities);
        }
    }
}